package com.corgi.test.bean;

import net.sf.cglib.beans.BeanCopier;

import java.lang.reflect.Array;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * CloneableBase
 *
 * @title: CloneableBase
 * @description:
 * @author: dengmiao
 * @create: 2019-12-21 13:01
 **/
public interface CloneableBase extends BaseCloneable {

    ConcurrentMap<Class<?>, BeanCopier> beanCopiers = new ConcurrentHashMap<>();

    @Override
    default Object deepClone() {
        try {
            Object clone = this.getClass().newInstance();
            BeanCopier copier = _createCopier(this.getClass());
            copier.copy(this, clone, (pojo, fieldType, fieldName) -> _clone(pojo));
            return clone;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    static Object _clone(Object bean) {
        if (bean == null) {
            return null;
        } else if (bean instanceof BaseCloneable) {
            return ((BaseCloneable) bean).deepClone();
        } else {
            if (bean.getClass().isArray() && !bean.getClass().getComponentType().equals(byte.class)) {
                int length = Array.getLength(bean);
                Object clone = Array.newInstance(bean.getClass().getComponentType(), length);
                for (int i = 0; i < length; i++) {
                    Array.set(clone, i, _clone(Array.get(bean, i)));
                }
                return clone;
            } else {
                return bean;
            }
        }
    }

    static BeanCopier _createCopier(Class<?> clz) {
        if (beanCopiers.containsKey(clz))
            return beanCopiers.get(clz);
        beanCopiers.putIfAbsent(clz, BeanCopier.create(clz, clz, true));
        return beanCopiers.get(clz);

    }
}
